
// 定义一个Dep 类
class Dep {
  constructor() {
    // 给每一个通过Dep类创建的对象 添加一个订阅者的集合
    //  将 使用到数据的 函数(这里方便理解就设置为函数) 收集到这个集合里面
    //  set 中元素不会重复, 保证 函数不会重复
    this.subscribers = new Set()
  }
//  收集 副作用 方法
  depend() {
    if(activeEffect) {
      //  集合中 添加对象使用 .add 
     this.subscribers.add(activeEffect)
   }
  }
//  执行 这些副作用 方法
  notify() {
    this.subscribers.forEach(effect =>{
     effect()
   })
  }
}

let activeEffect = null
function watchEffect(effect) {
  activeEffect = effect
  //  第一次就要执行一次 所有调用依赖的方法
  effect()
  activeEffect = null
}


// 设置 数据结构的最外层
//  map({key: value})  map 里面是一个个键值对   key 必须是 字符串
//  weakMap({key(对象): value})  key 必须是一个对象 ,弱引用
const targetMap = new WeakMap()
//  根据 传进来 的 target, key  返回dep
function getDep(target, key) {
  // 将传进来的 target对象  取出来相应的map 对象 保存value
  let depsMap = targetMap.get(target)
  if(!depsMap) {
    depsMap = new Map()
    //  形成我们 想要的数据结构     [{info}]
    targetMap.set(target,depsMap)
  }
  // 取出 具体的 dep 对象
  let dep = depsMap.get(key)
  if(!dep) {
    dep = new Dep()
    depsMap.set(key,dep)
  }
  return dep
}

//  vue3 中 对 raw 的数据劫持
// reactive() 函数中 要对传进来的 raw 对象进行劫持
function reactive(raw) {
  return new Proxy(raw, {
    //  获取数据的时候 会调用 get()
    get(target, key) {
      const dep = getDep(target, key)
      dep.depend()
      return target[key]
    },
    //  设置数据的时候会 调用 set()
    set(target, key, newValue) {
      const dep = getDep(target, key)
      target[key] = newValue
      dep.notify()
    }
  })
}


//
const proxy = reactive({name: "Eason"})
proxy.name = "信心花舍"


const info = reactive({age: 1974, name: "Eason"})
const song = reactive({title:"无条件"})

watchEffect(function (){
  console.log("effect1", info.age - 100, info.name);
})

watchEffect(function() {
  console.log("effect2", 2021-info.age + 3, info.name);
})

watchEffect(function() {
  console.log("effect3", song.title);
})

setTimeout(()=>{
  song.title = "沙龙"
},3000
)
